package com.ctrip.cap.ui;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Listeners;
import org.testng.xml.XmlTest;

import com.ctrip.cap.CapLogger;
import com.ctrip.cap.api.APIDriver;
import com.ctrip.cap.common.exception.CapException;
import com.ctrip.cap.exception.AppiumDriverException;
import com.ctrip.cap.internal.domain.Context;
import com.ctrip.cap.internal.performance.Profilers;
import com.ctrip.cap.internal.suite.ReporterSuiteListener;
import com.ctrip.cap.internal.suite.SuiteManListener;
import com.ctrip.cap.internal.test.MethodFilterChain;
import com.ctrip.cap.lanucher.AppiumConfig.DriverType;
import com.ctrip.cap.lanucher.Config;
import com.ctrip.cap.ui.UIConfig;
import com.ctrip.cap.lanucher.*;
import com.ctrip.cap.page.CapPage;
import com.ctrip.cap.reporter.CapReporter;

/**
 * <pre/>
 * 
 * @author sqou
 * 
 * @see CapPage better PageObject Practice
 * 
 */
@Listeners(value = { ReporterSuiteListener.class, UIJobSetUpListener.class,
		CapReporter.class })
public class UITest {

	private static final Logger iLogger = LoggerFactory
			.getLogger(UITest.class);

	private static final ThreadLocal<Context> UIContextHolder = new InheritableThreadLocal<>();

	private static final ThreadLocal<Throwable> exceptionHolder = new InheritableThreadLocal<>();
    
	protected static final Map<String, String> suiteParameters = new TreeMap<>(
			String.CASE_INSENSITIVE_ORDER);
	
	protected static WebDriver Driver;
	
	
	@BeforeSuite
	public void setUpLogger(ITestContext context) {
		iLogger.info("Order debug {}", Profilers.listenerOrder());
		CapLogger.setContext(UIContextHolder);
		Map<String, String> ps = context.getSuite().getXmlSuite()
				.getParameters();
		suiteParameters.putAll(ps);
		Config config = new Config();
		if(suiteParameters.get("DriverType").equals("ChromeDriver"))
		{
			config.setDriverType(DriverType.ChromeDriver);
			Driver = new ChromeDriver();
		}else if(suiteParameters.get("DriverType").equals("IEDriver"))
		{
			config.setDriverType(DriverType.IEDriver);
			Driver = new InternetExplorerDriver();
		}else if(suiteParameters.get("DriverType").equals("FirefoxDriver"))
		{
			config.setDriverType(DriverType.FirefoxDriver);
			Driver= new FirefoxDriver();
		};
		config.setPlatformName("PC");
		context.getSuite().setAttribute(SuiteManListener.CAP_CONFIG, config);
	}

	@BeforeMethod(alwaysRun = true)
	public final void setUpDriver(ITestContext testContext,
			Object[] parameters, Method method, XmlTest xmlTest) {
	
		UIContext context = new UIContext();
		try {
			context.setTestContext(testContext);
			context.setXmlTest(xmlTest);
			context.setMethod(method);
			UIContextHolder.set(context);
			MethodFilterChain.beforeMethod(context);
		} catch (Exception e) {
			exceptionHolder.set(e);
			throw new CapException("UITest Set up Driver", e);
		} finally {
			// context.closeQuietly();
		}

		iLogger.info("setup {} down", method.getName());

	}

	@AfterMethod(alwaysRun = true)
	public void destroyDriver(ITestContext testContext, ITestResult testResult,
			Method method) {
		iLogger.info("after destroy start {}", method.getName());

		UIContext context = (UIContext) UIContextHolder.get();
		if (context == null) {
			iLogger.warn("destroy driver abnormally");
			return;
		}

		try {
			context.setTestResult(testResult);
			MethodFilterChain.afterMethod(context);

			if (testResult.getStatus() == ITestResult.SKIP) {
				String hint = "New AppiumDriver(appium log="
						+ context.getDriver().toString() + ") failure";
				Throwable throwable = exceptionHolder.get();

				if (throwable != null)
					testResult.setThrowable(new AppiumDriverException(hint,
							throwable));
			}

		} catch (Exception t) {
			iLogger.warn("after ", t);
		} finally {
			context.closeQuietly();
			UIContextHolder.remove();
			exceptionHolder.remove();
		}

		iLogger.info("after destroy down {}", method.getName());

	}

	protected WebDriver getDriver() {
		//UIContext context = (UIContext) UIContextHolder.get();
		//return context.getDriver();
		return this.Driver;
	}	
	
	protected String getSuiteParameter(String key) {
		return suiteParameters.get(key);
	}
}
